package org.jeecg.common.aspect;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.aspect.annotation.ThirdPartyApi;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.properties.Api;
import org.jeecg.common.properties.ThirdPartyApiProperties;
import org.jeecg.common.util.ApiSignUtil;
import org.jeecg.common.util.SpringContextUtils;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.List;
import java.util.TreeMap;


/**
 * 第三方api切面
 *
 * @author zhanglei01
 * @date 2022/03/04
 */
@Aspect
@Component
@Order(1)
@Slf4j
public class ThirdPartyApiAspect {

    //30s超时30000
    public static final int REQUEST_EXPIRE_TIME = 30000;

    @Pointcut("@within(org.jeecg.common.aspect.annotation.ThirdPartyApi) || @annotation(org.jeecg.common.aspect.annotation.ThirdPartyApi)")
    public void pointCut() {

    }

    @Before("pointCut()")
    public void before(JoinPoint point) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> declaringClass = method.getDeclaringClass();
        //获取类注解
        ThirdPartyApi annotation4Class = declaringClass.getAnnotation(ThirdPartyApi.class);
        //获取方法注解
        ThirdPartyApi annotation = method.getAnnotation(ThirdPartyApi.class);
        //如果方法存在注解就使用方法的注解值
        if (annotation != null) {
            annotation4Class = annotation;
        }
        if (!annotation4Class.requestSign()) {
            return;
        }
        HttpServletRequest request = SpringContextUtils.getHttpServletRequest();
        String queryString = request.getQueryString();
        if (StringUtils.isBlank(queryString)) {
            throw new JeecgBootException("非法请求!");
        }
        String appId = request.getParameter("appId");
        String nonceStr = request.getParameter("nonceStr");
        String timestamp = request.getParameter("timestamp");
        String sign = request.getParameter("sign");
        if (StringUtils.isAnyBlank(appId, nonceStr, timestamp, sign)) {
            throw new JeecgBootException("非法请求!");
        }
        long requestTimestamp = Long.parseLong(timestamp);
        if (System.currentTimeMillis() - requestTimestamp > REQUEST_EXPIRE_TIME) {
            throw new JeecgBootException("签名超时!");
        }
        TreeMap<String, Object> treeMap = new TreeMap<>();
        treeMap.put("appId", appId);
        treeMap.put("nonceStr", nonceStr);
        treeMap.put("timestamp", timestamp);
        //获取调用方appSignKey
        ThirdPartyApiProperties bean = SpringContextUtils.getBean(ThirdPartyApiProperties.class);
        String appSignKey = "";
        if (ObjectUtil.isNotEmpty(bean) && bean.getConsumer().size() > 0) {
            List<Api> consumer = bean.getConsumer();
            for (Api api : consumer) {
                if (appId.equals(api.getAppId())) {
                    appSignKey = api.getAppSignKey();
                    break;
                }
            }
        }
        if (StringUtils.isBlank(appSignKey)) {
            throw new JeecgBootException("调用方appId不存在!");
        }
        //生成签名
        String reqSign = ApiSignUtil.getReqSign(treeMap, appSignKey);
        //比对生成的签名和url中的签名
        if (!reqSign.equals(sign)) {
            throw new JeecgBootException("签名校验失败!");
        }
    }

    @AfterReturning(returning = "object", pointcut = "pointCut()")
    public void afterReturning(JoinPoint point, Object object) throws Throwable {
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Class<?> declaringClass = method.getDeclaringClass();
        ThirdPartyApi annotation4Class = declaringClass.getAnnotation(ThirdPartyApi.class);
        ThirdPartyApi annotation = method.getAnnotation(ThirdPartyApi.class);
        if (annotation != null) {
            annotation4Class = annotation;
        }
        if (!annotation4Class.responseZip()) {
            return;
        }
        Result result = (Result) object;
        if (result.isSuccess()) {
            Object resultBody = result.getResult();
            //gzip压缩后Base64
            String gzipStr = ApiSignUtil.gzip(JSON.toJSONString(resultBody));
            result.setResult(gzipStr);
        }
    }
}
